﻿//
// "Bump Mapping"
//  Ygor Speranza
//   - base windows GL Context code by Blaine Hodge
//   - .OBJ loading by dphoware (http://www.dhpoware.com/demos/glObjViewer.html)
//   - orange model by 3dExtras (http://www.3dxtras.com/)
//   - bump map by CrazyBump (http://www.crazybump.com)
//   - image loading code by Paul Baker

#include <fstream>
#include <math.h>
#include <string>

#include "scene.h"
#include "DeformableMesh.h"
#include "shaders.h"
#include "vmatrix.h"

// gl includes
#include "gl\glew.h"
#include "gl\wglew.h"
#include "gl\GL.h"

// performance measuring
#include "consoleoutput.h"
#include "fpsmeasurer.h"

#define VERTEX_SHADER	"vertex.sl"
#define FRAGMENT_SHADER "fragment.sl"

// forward declarations
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC);
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC);
static GLuint CreateShaderProgram( const char* vertexShader, const char *fragmentShader );

enum AppState {
	APP_STATE_RUNNING,
	APP_STATE_PAUSED,
	APP_STATE_QUIT
};

// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
				   LPSTR lpCmdLine, int iCmdShow)
{
	WNDCLASS wc;
	HWND hWnd;
	HDC hDC;
	HGLRC hRC;
	MSG msg;
	AppState appState = APP_STATE_RUNNING;
	const float DT = 1.0f;
	
	// register window class
	wc.style = CS_OWNDC;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "GLSample";
	RegisterClass( &wc );
	
	// create main window
	hWnd = CreateWindow( 
		"GLSample", "Meshless Deformation", 
		WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
		0, 0, 1200, 800,
		NULL, NULL, hInstance, NULL 
	);
	
	// enable OpenGL for the window
	EnableOpenGL( hWnd, &hDC, &hRC );

	// create and assign shader program
	char* next = NULL;
	char* param1 = strtok_s(lpCmdLine, " ", &next);
	char* param2 = strtok_s(next, " ", &next);
	//char* param3 = strtok_s(next, " ", &next);
	//char* param4 = strtok_s(next, " ", &next);
	//char* param5 = strtok_s(next, " ", &next);

	if(param1 == NULL) param1 = "orange.obj";
	//if(param2 == NULL) param2 = "lava05Bump.bmp";
	if(param2 == NULL) param2 = "1";
	//if(param4 == NULL) param4 = "1";
	//if(param5 == NULL) param4 = "1";

	GLubyte programId = CreateShaderProgram( VERTEX_SHADER, FRAGMENT_SHADER );
	glUseProgram( programId );

	Scene scene( param1, "texturename", atoi(param2) );
	scene.setRenderingMode( RenderingMode::RENDERING_MODE_POINT );

	DeformableMesh& model = scene.getModel();

	for( int i = 0; i < 81; i++ )
	{
		//model.setVertexBlockMode( i, VERTEX_BLOCK_MODE_LOCK_Y );
	}
	for( int i = 100; i < 200; i++ )
	{
		model.setVertexBlockMode( i, VERTEX_BLOCK_MODE_LOCK_ALL );
	}

	//scene.getModel().blockVertex( 20 );
	//scene.getModel().blockVertex( 21 );
	//scene.getModel().blockVertex( 22 );
	//scene.getModel().blockVertex( 23 );

	// loading model
	//ModelOBJ* model = new ModelOBJ();
	//model->import( param1 );

	// generating model info buffer
	//int numberOfTriangles = model->getNumberOfIndices() / 3;
	//float* vertexInfo = (float*) malloc(sizeof(float) * numberOfTriangles * 39 );
	//GLuint positionBufferObject;
	//AssignModelBuffer( &positionBufferObject, model, vertexInfo, 0, true );

	// loading normal map texture
	//GLuint texture;
	//IMAGE img;
	//img.Load( param2 );
    
	// generate the texture with the loaded data and bind the texture to it’s array
	//glGenTextures( 1, &texture );
 //   glBindTexture( GL_TEXTURE_2D, texture );
 //   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
 //   
 //   glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 //   glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//glActiveTexture( GL_TEXTURE0 );

	//// generate the texture
 //   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, img.width, img.height,
 //       0, img.format, GL_UNSIGNED_BYTE, img.data);
	glCullFace( GL_BACK );
	glEnable( GL_CULL_FACE );

	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
	glDepthFunc(GL_LEQUAL);
	glDepthRange(0.0f, 1.0f);	

	int my_sampler_uniform_location = glGetUniformLocation( programId, "normalTex" );
	glUniform1i(my_sampler_uniform_location, 0);
	
	// colors
	GLuint ambColorIndex = glGetUniformLocation(programId, "ambientColor");
	float ambientColor[4] = { 0.0f/255.0f, 50.0f/255.0f, 0.0f/255.0f, 1.0f };
	glUniform4fv(ambColorIndex, 1, ambientColor);

	GLuint difColorIndex = glGetUniformLocation(programId, "diffuseColor");
	float diffColor[4] = { 0.0, 0.23f, 0.23f, 1.0f };
	glUniform4fv(difColorIndex, 1, diffColor);

	GLuint spColorIndex = glGetUniformLocation(programId, "specularColor");
	float specColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glUniform4fv(spColorIndex, 1, specColor);

	GLuint shininessIndex = glGetUniformLocation(programId, "shininess");
	float shininess[1] = {512.0f};
	glUniform1fv(shininessIndex, 1, shininess);

	// transformations
	float mvpMatrix[16];
	VMatrix *stack = new VMatrix();
	
	float persp[4] = { 70.0f, 2.0f, 0.1f, 5.0f };
	stack->Perspective( persp[0], persp[1], persp[2], persp[3] );

	float scale = 0.5f;
	float camera[3] = { 0.0f, 0.0f, -2.0f };
	float translate[3] =  { -0.1f, 0.0f, -2.2f };
	float look[3] = { 0.0f, 0.0f, 0.0f };

	//float lookX = 0.0, lookY = -6.0f, lookZ = 0.0f;
	stack->LookAt( look[0], look[1], look[2], camera[0], camera[1], camera[2], 0.0f, 1.0f, 0.0f);
	stack->Translate( translate[0], translate[1], translate[2] );
	stack->Scale( scale, scale, scale );
	GLuint mvpMatrixIndex = glGetUniformLocation(programId, "mvpMatrix");
	stack->GetMatrix(mvpMatrix);
	glUniformMatrix4fv(mvpMatrixIndex, 1, false, (const GLfloat*) mvpMatrix);

	// mv matrix
	float mvMatrix[16];
	stack->LoadIdentity();
	stack->LookAt( look[0], look[1], look[2], camera[0], camera[1], camera[2], 0.0f, 1.0f, 0.0f);
	stack->Translate( translate[0], translate[1], translate[2] );
	stack->Scale( scale, scale, scale );
	GLuint mvMatrixIndex = glGetUniformLocation(programId, "mvMatrix");
	stack->GetMatrix(mvMatrix);
	glUniformMatrix4fv(mvMatrixIndex, 1, false, (const GLfloat*) mvMatrix);

	// normal matrix
	float normalMatrix[16];
	GLuint normalMatrixIndex = glGetUniformLocation(programId, "normMatrix");
	stack->GetMatrixIT(normalMatrix);
	if( normalMatrixIndex != GL_INVALID_VALUE && normalMatrixIndex != GL_INVALID_OPERATION )
	{
		glUniformMatrix4fv(normalMatrixIndex, 1, false, (const GLfloat*) normalMatrix);
	}
	
	CONSOLE( " Starting... " );
	appState = APP_STATE_PAUSED;
	model.setSimulationStepByStep( true );

	// benchmark measuring
	const int loopsUntilMSecsPrint = 50;
	int loopsRemaining = loopsUntilMSecsPrint;

	FPSMeasurer fpsMeasurer;
	
	while ( appState != APP_STATE_QUIT )
	{
		fpsMeasurer.measure();
		
		loopsRemaining--;
		if( loopsRemaining < 0 )
		{
			if( appState == APP_STATE_RUNNING )
				fpsMeasurer.print();

			loopsRemaining = loopsUntilMSecsPrint;
		}

		// update of our program
		if( appState == APP_STATE_RUNNING )
			scene.update( DT );
		
		// check for input messages
		if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )  )
		{		
			// handle or dispatch messages
			if ( msg.message == WM_QUIT ) 
			{
				appState = APP_STATE_QUIT;
			}
			else if( msg.message == WM_KEYDOWN )
			{
				switch( msg.wParam )
				{

				case 188: // "<" key
					model.setRigidity( model.getRigidity() - 0.1f );
					break;

				case 190: // ">" key
					model.setRigidity( model.getRigidity() + 0.1f );
					break;

				case 13: // enter key
					appState = appState == APP_STATE_PAUSED? APP_STATE_RUNNING: APP_STATE_PAUSED;
					CONSOLE( (appState == APP_STATE_PAUSED? "Simulation Paused.\n" : "Simulation resumed.\n") );
					model.setSimulationStepByStep( appState == APP_STATE_PAUSED );

					break;

				case 32: // space key
					if (appState == APP_STATE_PAUSED)
						scene.update( DT );
					break;

				case 69: // e key
					model.rotateVertex( 0, -0.85f );
					break;

				case 82: // r key
					model.rotateVertex( 0, 0.85f );
					break;

				case 79: // o key
					model.setPlasticityMode( (PlasticityMode) ( ( model.getPlasticityMode() + 1 ) % 2 ) );
					break;

				case 80: // p key
					scene.setRenderingMode( (RenderingMode) ( ( scene.getRenderingMode() + 1 ) % 2 ) );
					break;

				case 70: // f key
					for( int i = 0; i < model.getNumberOfVertices(); i++)
					{
						float x, y, z;
						model.getCenterOfMass( &x, &y, &z );
						model.moveVertex( i, model.getVertex( i ).position[0] > x? 0.19f: -0.19f, 0.0f, 0.0f );
						
					}
					break;

				case 40: // down key
					model.moveMesh( 0.0f, -0.03f );
					//model.moveVertex( 11, 0.3f, 0.0f );
					break;

				case 38: // up key
					model.moveMesh( 0.0f, 0.03f );
					break;

				case 37: // left key
					model.moveMesh( -0.03f, 0.0f );
					break;

				case 39: // right key
					model.moveMesh( 0.03f, 0.0f );
					break;

				case 35:
					translate[1] -= 0.1f;
					break;

				case 46:
					translate[0] += 0.1f;
					break;

				case 36:
					translate[1] += 0.1f;
					break;

				case 34:
					translate[0] -= 0.1f;
					break;

				case 45:
					translate[2] += 0.1f;
					break;

				case 33:
					translate[2] -= 0.1f;
					break;

				case 107:
					scale *= 1.02f;
					break;

				case 109:
					scale *= 0.98f;
				}
				
				/*std::stringstream sstr;
				sstr << "key-pressed: " << msg.wParam << "\n";
				sstr << "Translate (" << translate[0] << ", " << translate[1] << ", " << translate[2] << ")\n";
				OutputDebugString( (LPCTSTR) sstr.str().data() );*/

				//GLuint translateIndex = glGetUniformLocation(programId, "translate");
				//glUniform3f(translateIndex, translate[0], translate[1], translate[2]);


				stack->LoadIdentity();
				stack->Perspective( persp[0], persp[1], persp[2], persp[3] );
				stack->LookAt( look[0], look[1], look[2], camera[0], camera[1], camera[2], 0.0f, 1.0f, 0.0f);
				stack->Translate( translate[0], translate[1], translate[2] );
				stack->Scale( scale, scale, scale );
				GLuint mvpMatrixIndex = glGetUniformLocation(programId, "mvpMatrix");
				stack->GetMatrix(mvpMatrix);
				glUniformMatrix4fv(mvpMatrixIndex, 1, false, (const GLfloat*) mvpMatrix);

				// mv matrix
				float mvMatrix[16];
				stack->LoadIdentity();
				stack->LookAt( look[0], look[1], look[2], camera[0], camera[1], camera[2], 0.0f, 1.0f, 0.0f);
				stack->Translate( translate[0], translate[1], translate[2] );
				stack->Scale( scale, scale, scale );
				GLuint mvMatrixIndex = glGetUniformLocation(programId, "mvMatrix");
				stack->GetMatrix(mvMatrix);
				glUniformMatrix4fv(mvMatrixIndex, 1, false, (const GLfloat*) mvMatrix);

				// normal matrix
				float normalMatrix[16];
				GLuint normalMatrixIndex = glGetUniformLocation(programId, "normMatrix");
				stack->GetMatrixIT(normalMatrix);
				if( normalMatrixIndex != GL_INVALID_VALUE && normalMatrixIndex != GL_INVALID_OPERATION )
				{
					glUniformMatrix4fv(normalMatrixIndex, 1, false, (const GLfloat*) normalMatrix);
				}
			}
			else
			{
				TranslateMessage( &msg );
				DispatchMessage( &msg );
			}
			
		} 
		//else 
		//{
			//glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
			//glClear(GL_COLOR_BUFFER_BIT);

			//// updating our model
			//AssignModelBuffer( &positionBufferObject, model, vertexInfo, time );

			//glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
			//glEnableVertexAttribArray(0);
			//glEnableVertexAttribArray(1);
			//glEnableVertexAttribArray(2);
			//glEnableVertexAttribArray(3);
			//glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
			//glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float) * numberOfTriangles * 12));
			//glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float) * numberOfTriangles * 24));
			//glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float) * numberOfTriangles * 30));

			//glDrawArrays(GL_TRIANGLES, 0, numberOfTriangles * 3 );

			//glDisableVertexAttribArray(0);
			//glDisableVertexAttribArray(1);
			//glDisableVertexAttribArray(2);
			//glDisableVertexAttribArray(3);

			scene.draw();
			SwapBuffers( hDC );			
		//}
	}
	glUseProgram(0);

	// shutdown OpenGL
	DisableOpenGL( hWnd, hDC, hRC );

	// destroy the window explicitly
	DestroyWindow( hWnd );
	
	return msg.wParam;
}

// Window Procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	switch (message)
	{
		
	case WM_CREATE:
		return 0;
		
	case WM_CLOSE:
		PostQuitMessage( 0 );
		return 0;
		
	case WM_DESTROY:
		return 0;
		
	case WM_KEYDOWN:
		switch ( wParam )
		{
			
		case VK_ESCAPE:
			PostQuitMessage(0);
			return 0;
			
		}
		return 0;
	
	default:
		return DefWindowProc( hWnd, message, wParam, lParam );
			
	}
	
}

// Enable OpenGL
void EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC)
{
	PIXELFORMATDESCRIPTOR pfd;
	int format;
	
	// get the device context (DC)
	*hDC = GetDC( hWnd );
	
	// set the pixel format for the DC
	ZeroMemory( &pfd, sizeof( pfd ) );
	pfd.nSize = sizeof( pfd );
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 16;
	pfd.iLayerType = PFD_MAIN_PLANE;
	format = ChoosePixelFormat( *hDC, &pfd );
	SetPixelFormat( *hDC, format, &pfd );
	
	// create and enable the render context (RC)
	*hRC = wglCreateContext( *hDC );
	wglMakeCurrent( *hDC, *hRC );

	// starting glew
	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		CONSOLE( "GLEW is not initialized!" );
	}
}

// Disable OpenGL
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC)
{
	wglMakeCurrent( NULL, NULL );
	wglDeleteContext( hRC );
	ReleaseDC( hWnd, hDC );
}

// Creating Shader Program
static GLuint CreateShaderProgram ( const char *vf, const char *fs )
{
	std::ifstream file ( vf );
	std::string vsource;
	char line[100];
	if (file.is_open())
	{
		while ( file.good() )
		{
			file.getline(line, 100);
			vsource.append(line);
			vsource.append("\n");
		}
		file.close();
	}

	file.open( fs );
	std::string fsource;
	if (file.is_open())
	{
		while ( file.good() )
		{
			file.getline(line, 100);
			fsource.append(line);
			fsource.append("\n");
		}
		file.close();
	}

	// vertex shader
	GLuint v_id = createShader(GL_VERTEX_SHADER, vsource.c_str());
	if (v_id==0) {
		printf("Could not create vertex shader object");
		exit(0);
	}

	const char* vvv =  vsource.c_str();
	glShaderSource(v_id, 1, &vvv, 0);
	compileShader(v_id);

	GLsizei size = 0;
	GLcharARB charARB[300];
	glGetInfoLogARB(v_id, 300, &size, charARB);

	CONSOLE( "Vertex shader error message: " << charARB );

	// fragment shader
	GLuint f_id = createShader(GL_FRAGMENT_SHADER, fsource.c_str());
	if (f_id==0) {
		printf("Could not create fragment shader object");
		exit(0);
	}

	glGetInfoLogARB(f_id, 300, &size, charARB);
	CONSOLE( "Fragment shader error message: " << charARB );

	const char *fff = fsource.c_str();
	glShaderSource(f_id, 1, &fff, 0);
	compileShader(f_id);

	// program
	GLuint p_id = glCreateProgram();
	if (p_id == 0) {
		printf("Could not create program object");
		exit(0);
	}

	// vertex shader attributes
	glBindAttribLocation(p_id, 0, "vPos");
	//glBindAttribLocation(p_id, 1, "vNormal");
	//glBindAttribLocation(p_id, 2, "vTexture");
	//glBindAttribLocation(p_id, 3, "vTangent");
	glBindAttribLocation(p_id, 1, "clusterIndex");

	// shader attaching and linking
	glAttachShader(p_id, v_id);
	glAttachShader(p_id, f_id);
	linkProgram(p_id);
	return p_id;
}

//void AssignModelBuffer( GLuint* bufferPointer, ModelOBJ* model, float* modelBuffer, float time, bool firstTime )
//{
//	// updating model
//	//const int nVertices = model->getNumberOfVertices();
//	//float vertexBuffer[nVertices] = model->getVertexBuffer();
//	//for(int i = 0; i < nVertices; i++) 
//	//{
//	//	const ModelOBJ::Vertex &v = model->getVertex(i);
//	//	model->set
//
//	//}
//
//	int numberOfTriangles = model->getNumberOfIndices() / 3;
//	for(int i = 0; i < numberOfTriangles; i++) 
//	{
//		for( int j = 0; j < 3; j++)
//		{
//			const ModelOBJ::Vertex &v = model->getVertex(model->getIndexBuffer()[i*3 + j]);
//			modelBuffer[i*12 + j*4    ] = v.position[0]; 
//			modelBuffer[i*12 + j*4 + 1] = v.position[1];			
//			modelBuffer[i*12 + j*4 + 2] = v.position[2];
//			modelBuffer[i*12 + j*4 + 3] = 1.0f;
//		}
//	}
//
//	// generating normals
//	for(int i = 0; i < numberOfTriangles; i++) 
//	{
//		for( int j = 0; j < 3; j++)
//		{
//			const ModelOBJ::Vertex &v = model->getVertex(model->getIndexBuffer()[i*3 + j]);
//			modelBuffer[numberOfTriangles*12 + i*12 + j*4    ] = v.normal[0];
//			modelBuffer[numberOfTriangles*12 + i*12 + j*4 + 1] = v.normal[1];
//			modelBuffer[numberOfTriangles*12 + i*12 + j*4 + 2] = v.normal[2];
//			modelBuffer[numberOfTriangles*12 + i*12 + j*4 + 3] = 1.0f;
//		}
//	}
//
//	// texture coordinates
//	for(int i = 0; i < numberOfTriangles; i++) 
//	{
//		for( int j = 0; j < 3; j++)
//		{
//			ModelOBJ::Vertex v = model->getVertex(model->getIndexBuffer()[i*3 + j]);
//			  
//			modelBuffer[numberOfTriangles*24 + i*6 + j*2    ] = v.texCoord[0];
//			modelBuffer[numberOfTriangles*24 + i*6 + j*2 + 1] = v.texCoord[1];
//		}
//	}
//
//	// tangent vectors
//	for(int i = 0; i < numberOfTriangles; i++) 
//	{
//		long i1 = model->getIndexBuffer()[i*3];
//        long i2 = model->getIndexBuffer()[i*3 + 1];
//        long i3 = model->getIndexBuffer()[i*3 + 2];
//        
//		const float* v1 = model->getVertex(i1).position;
//        const float* v2 = model->getVertex(i2).position;
//        const float* v3 = model->getVertex(i3).position;
//        
//		const float* w1 = model->getVertex(i1).texCoord;
//        const float* w2 = model->getVertex(i2).texCoord;
//        const float* w3 = model->getVertex(i3).texCoord;
//        
//        float x1 = v2[0] - v1[0];
//        float x2 = v3[0] - v1[0];
//        float y1 = v2[1] - v1[1];
//        float y2 = v3[1] - v1[1];
//        float z1 = v2[2] - v1[2];
//        float z2 = v3[2] - v1[2];
//        
//        float s1 = w2[0] - w1[0];
//        float s2 = w3[0] - w1[0];
//        float t1 = w2[1] - w1[1];
//        float t2 = w3[1] - w1[1];
//        
//        float r = 1.0f / (s1 * t2 - s2 * t1);
//
//		// we do not interpolate the tangents here for all incident triangles normals
//		modelBuffer[numberOfTriangles*30 + i*9     ] = (t2 * x1 - t1 * x2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 1 ] = (t2 * y1 - t1 * y2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 2 ] = (t2 * z1 - t1 * z2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 3 ] = (t2 * x1 - t1 * x2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 4 ] = (t2 * y1 - t1 * y2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 5 ] = (t2 * z1 - t1 * z2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 6 ] = (t2 * x1 - t1 * x2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 7 ] = (t2 * y1 - t1 * y2) * r;
//		modelBuffer[numberOfTriangles*30 + i*9 + 8 ] = (t2 * z1 - t1 * z2) * r;
//	}
//
//	if( firstTime )
//	{
//		glGenBuffers(1, bufferPointer);
//	}
//	glBindBuffer(GL_ARRAY_BUFFER, *bufferPointer);
//    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * numberOfTriangles * 39, modelBuffer, GL_STREAM_DRAW);
//}